
#include "main.h"

#define DEVINCE_TYPE "device_type"
#define VENDOR "vendor"
#define OVERLAY_VERSION "overlay_version"
#define NODE_ID "NodeId"
#define FIRMWARE_PATH "/etc/version"
#define FACTORY_OVERLAY_VERSION_PATH "/etc/overlay_info"

deviceTypeDef deviceConfig;

/**
 * @brief  Get the string from config JSON
 * @param  stringbuff: string buffer
 * @param  filedir: config file direction
 * @param  maxlen: maximum copy bytes
 * @retval return TRUE if success, or return FALSE if failed
 */
uint8_t getConfig(uint8_t *stringbuff, const char *filedir,int maxlen)
{

    int fd = 0;
    uint32_t read_len = 0;
    struct stat file_stat;

    fd = open(filedir, O_RDONLY);
    if (fd == -1) {
        if (errno == ENOENT) {
            perror("config file not exist."); 
        } else {
            perror("config file open failed."); 
        }
        return FALSE; // 返回错误代码
    }
    // 获取文件大小
    if (fstat(fd, &file_stat) == -1) {
        perror("fstat get failed.");
        close(fd);
        return 1;
    }
    off_t file_size = file_stat.st_size;
    
    // 在调用 read() 函数之前添加如下检查：
    if (file_size >= maxlen) {
        printf("Error: stringbuff buffer too small.\n");
        close(fd);
        return FALSE;
    }

    read_len = read(fd, stringbuff, maxlen);
    if (read_len == -1)
    {
        printf("read error!\r\n");
        close(fd);
        return FALSE;
    }
    // 在调用 read() 函数之后添加：
    stringbuff[read_len] = '\0'; 

    close(fd);
    return TRUE;
}

/**
 * @brief string2Json
 *
 * @param str: input data
 * @return cJSON*
 */
cJSON *string2Json(uint8_t *str)
{

    if (str == NULL)
    {
        return NULL;
    }

    cJSON *ret = cJSON_Parse((char *)str);
    if (ret == NULL)
    {
        printf("string2Json: ret == NULL!\n");
        return NULL;
    }
    else
    {
        if (ret->type != cJSON_Object)
        {
            printf("string2Json: ret->type error!\n");
            return NULL;
        }
    }

    return ret;
}

/**
 * @brief Get the devinfoMsg object
 *
 * @param data
 * @return uint8_t
 */
static uint8_t get_devinfoMsg(cJSON *data)
{

    cJSON *devtype = NULL;
    cJSON *vender = NULL;
    cJSON *overlayVersion = NULL;
    cJSON *nodeId = NULL;
    int infolen = 0;

    if (data == NULL)
    {
        printf("get_devinfoMsg: data == NULL!\n");
        return FALSE;
    }
    else
    {
        if (data->type != cJSON_Object)
        {
            printf("get_devinfoMsg: data->type error!\n");
            return FALSE;
        }
    }

    memset(&deviceConfig,'\0',sizeof(deviceConfig));

    devtype = cJSON_GetObjectItem(data, DEVINCE_TYPE);
    if (devtype == NULL)
    {
        printf("get_devinfoMsg: %s == NULL!\n",DEVINCE_TYPE);
    }
    else
    {
        if (devtype->type != cJSON_String)
        {
            printf("get_devinfoMsg: %s->type error!\n",DEVINCE_TYPE);
        }
        else
        {
            infolen = strlen(devtype->valuestring);
            (infolen >= DEV_INFO_LEN) ? (infolen = DEV_INFO_LEN -1) : (infolen = infolen);
            strncpy(deviceConfig.deviceType,devtype->valuestring,infolen);
            deviceConfig.deviceType[infolen]='\0';
        }
    }

    vender = cJSON_GetObjectItem(data, VENDOR);
    if (vender == NULL)
    {
        printf("get_devinfoMsg: %s == NULL!\n",VENDOR);
    }
    else
    {
        if (vender->type != cJSON_String)
        {
            printf("get_devinfoMsg: %s->type error!\n",VENDOR);
        }
        else
        {
            infolen = strlen(vender->valuestring);
            (infolen >= DEV_INFO_LEN) ? (infolen = DEV_INFO_LEN -1) : (infolen = infolen);
            strncpy(deviceConfig.vendor,vender->valuestring,infolen);
            deviceConfig.vendor[infolen]='\0';
        }
    }

    overlayVersion = cJSON_GetObjectItem(data, OVERLAY_VERSION);
    if (overlayVersion == NULL)
    {
        printf("get_devinfoMsg: %s  == NULL!\n",OVERLAY_VERSION);
    }
    else
    {
        if (overlayVersion->type != cJSON_String)
        {
            printf("get_devinfoMsg: %s->type error!\n",OVERLAY_VERSION);
        }
        else
        {
            infolen = strlen(overlayVersion->valuestring);
            (infolen >= DEV_INFO_LEN) ? (infolen = DEV_INFO_LEN -1) : (infolen = infolen);
            strncpy(deviceConfig.overlayVersion,overlayVersion->valuestring,infolen);
            deviceConfig.overlayVersion[infolen]='\0';
        }
    }

    nodeId = cJSON_GetObjectItem(data, NODE_ID);
    if (nodeId == NULL)
    {
        printf("get_devinfoMsg: %s  == NULL!\n",NODE_ID);
    }
    else
    {
        if (nodeId->type != cJSON_String)
        {
            printf("get_devinfoMsg: %s->type error!\n",NODE_ID);
        }
        else
        {
            infolen = strlen(nodeId->valuestring);
            (infolen >= DEV_INFO_LEN) ? (infolen = DEV_INFO_LEN -1) : (infolen = infolen);
            strncpy(deviceConfig.nodeId,nodeId->valuestring,infolen);
            deviceConfig.nodeId[infolen]='\0';
        }
    }

    cJSON_Delete(data);

    //获取factureOverlayVersion 信息
    if (!getConfig(deviceConfig.factureOverlayVersion, FACTORY_OVERLAY_VERSION_PATH,DEV_INFO_LEN))
    {
        printf("get_devinfoMsg: get deviceConfig.factureOverlayVersion failed!\n");
    }
    //去掉末尾换行
    for(int i = 0; i < strlen(deviceConfig.factureOverlayVersion); i++)
    {
        if('\n' == deviceConfig.factureOverlayVersion[i])
        {
            deviceConfig.factureOverlayVersion[i] = '\0';
            break;
        }
    }

    //获取firmware version 信息
    if (!getConfig(deviceConfig.firmwareVersion, FIRMWARE_PATH,DEV_INFO_LEN))
    {
        printf("get_devinfoMsg: get deviceConfig.firmwareVersion failed!\n");
    }
    //去掉末尾换行
    for(int i = 0; i < strlen(deviceConfig.firmwareVersion); i++)
    {
        if('\n' == deviceConfig.firmwareVersion[i])
        {
            deviceConfig.firmwareVersion[i] = '\0';
            break;
        }
    }

    return TRUE;
}

/**
 * @brief 获取当前用户，判断是否为root用户
 * @retval 0为成功，否则返回错误-1
 */
static int check_root_user_name(void) {
    // 获取当前进程的用户ID
    if (getuid() == 0) {
        return 0;  // 当前是 root 用户
    }
    return -1;  // 当前不是 root 用户
}

/**
 * @brief set config information
 * @param coninforstr config information
 * @return 成功返回0，失败返回-1
 */
int set_configinfo(const char *coninfo)
{
    uint8_t conf_str[JSON_LEN] = {0};
    char keyvalue[128] = {0};
    char valuestr[128] = {0};
    cJSON *config = NULL,*devtype = NULL;
    FILE *out_file = NULL;
    int ret = 0;

    //获取当前用户，只有root用户才有权限
    if(check_root_user_name())
    {
        fprintf(stderr, "user permission fail\n");
        return -1;
    }

    // 使用 sscanf 从字符串中提取 key 和 value
    if (sscanf(coninfo, "%127[^=]=%127[^\n]", keyvalue, valuestr) == 2) {
        // 去除 value 两端的双引号
        if (valuestr[0] == '"' && valuestr[strlen(valuestr) - 1] == '"') {
            // 移动字符，去掉双引号
            memmove(valuestr, valuestr + 1, strlen(valuestr) - 2);
            valuestr[strlen(valuestr) - 2] = '\0';  // 结束符
        }
    } else {
        printf("argv invalid format,tip: {nodename}=\"newvalue\"\n");
        return -1;
    }

    //获取配置信息
    if (!getConfig(conf_str, CONFIG_FILE_DIR, JSON_LEN))
    {
        printf("set_configinfo: getConfig failed!\n");
        return -1;
    }
    else
    {
        config = string2Json(conf_str);
        if (config == NULL)
        {
            printf("set_configinfo: string2Json error!\n");
            return -1;
        }
    }

    devtype = cJSON_GetObjectItemCaseSensitive(config, keyvalue);
    if (devtype == NULL)
    {
        printf("set_configinfo: %s key value does not exist!\n",keyvalue);
        ret = -1;
        goto JSON_ERR;
    }
    else
    {
        // 键值对存在，更新其值
        cJSON_SetValuestring(devtype, valuestr);

        out_file = fopen(CONFIG_FILE_DIR, "w");
        if (out_file == NULL) {
            perror("open file error");
            ret = -1;
            goto JSON_ERR;
        }
        fseek(out_file, 0, SEEK_SET);  // 回到文件开头

        // 将 JSON 对象转换为字符串
        char *json_string = cJSON_Print(config);
        if (json_string == NULL) {
            printf("Error: Failed to print JSON\n");
            fclose(out_file);
            ret = -1;
            goto JSON_ERR;
        }

        // 写入数据
        fwrite(json_string, 1, strlen(json_string), out_file);

        // 释放内存
        free(json_string);
        fclose(out_file);
        out_file = NULL;
        printf("update config successfully. key: %s value: %s\n",keyvalue,valuestr);
    }

JSON_ERR:
    cJSON_Delete(config);
    config = NULL;
    return ret;
}

/**
 * @brief Get the configuration object
 *
 * @return uint8_t
 */
uint8_t get_configuration(void)
{
    static uint8_t conf_str[JSON_LEN] = {0};
    cJSON *config;

    if (!getConfig(conf_str, CONFIG_FILE_DIR,JSON_LEN))
    {
        printf("get_configuration: getConfig failed!\n");
        return FALSE;
    }

    config = string2Json(conf_str);

    if (config == NULL)
    {
        printf("get_configuration: string2Json error!\n");
        return FALSE;
    }

    if (!get_devinfoMsg(config))
    {
        printf("get_configuration: get_devinfoMsg error!\n");
        return FALSE;
    }

    return TRUE;
}

/**
 * @brief 检验网关操作系统型号
 * @param data
 * @return uint8_t   
        FALSE 0 :  or no T
        TRUE 1 :   if D9_OPENWRT or D9_EULAR, 网关
 */
int check_firmware_version(char *firmware_version)
{
    char *type = NULL;
    char temp[5];
    int  chip_type = 0;

    /* firmware_version:T04D20221020M02V30D
       ：T：表示操作系统和芯片类型
       ：D：表示日期
       ：M：表示类型
       ：V：表示版本
    */
    type = strstr(firmware_version, "T");
    if (type == NULL) 
    {
        printf("check_firmware_version error!\n");
        return FALSE;
    }

    memset(temp, 0x00, sizeof(temp));
    memcpy(temp, type + 1, 2);
    chip_type = atoi(temp);
    if ((chip_type != D9_OPENWRT) && (chip_type != D9_EULAR))   // 芯片类型是否为D9
    {
        return FALSE;//不是D9
    }

    return TRUE; //是D9
}
